/**
 * 
 */
package edu.umd.clip.lm.model.data;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.*;

/**
 * @author Denis Filimonov <den@cs.umd.edu>
 *
 */
public class BufferedInputChannel implements ReadableByteChannel {
	private final ReadableByteChannel input;
	// the buffers share the data but have different points
	// inBuffer is used to to get data from the input
	// outBuffer is used to get data out to consumers
	private ByteBuffer buffer; 
	//private ByteBuffer outBuffer;
	
	private final int bufferSize;
	public final static int DEFAULT_BUFFER_SIZE = 1024*1024;
	
	
	public BufferedInputChannel(ReadableByteChannel input) {
		this(input, DEFAULT_BUFFER_SIZE);
	}
	
	/**
	 * @param input
	 * @param bufferSize
	 */
	public BufferedInputChannel(ReadableByteChannel input, int bufferSize) {
		this.input = input;
		this.bufferSize = bufferSize;
	}

	/* (non-Javadoc)
	 * @see java.nio.channels.ReadableByteChannel#read(java.nio.ByteBuffer)
	 */
	@Override
	public synchronized int read(ByteBuffer dst) throws IOException {
		if (buffer == null) {
			buffer = ByteBuffer.allocate(bufferSize);
			input.read(buffer);
			buffer.flip();
		}
		int readBytes = 0;
		while(dst.hasRemaining()) {
			if (buffer.remaining() == 0) {
				buffer.clear();
				int bytes = input.read(buffer);
				if (bytes == -1 && readBytes == 0) {
					// EOF
					return -1;
				}
				buffer.flip();
			}
			if (!buffer.hasRemaining()) return readBytes;
			
			int size = Math.min(dst.remaining(), buffer.remaining());
			readBytes += size;
			int outBufferPosition = buffer.position();
			dst.put(buffer.array(), outBufferPosition, size);
			buffer.position(outBufferPosition + size);
		}
		return readBytes;
	}

	/* (non-Javadoc)
	 * @see java.nio.channels.Channel#close()
	 */
	@Override
	public synchronized void close() throws IOException {
		input.close();
		buffer = null;
	}

	/* (non-Javadoc)
	 * @see java.nio.channels.Channel#isOpen()
	 */
	@Override
	public synchronized boolean isOpen() {
		return input.isOpen();
	}

}
